package com.zc.manager.device.service.impl;

import cn.hutool.core.date.DateUtil;
import com.zc.component.dashboard.DashboardManager;
import com.zc.component.dashboard.MeasurementParameter;
import com.zc.component.dashboard.SimpleMeasurementValue;
import com.zc.component.dashboard.web.request.DashboardMeasurementRequest;
import com.zc.component.dashboard.web.response.DashboardMeasurementResponse;
import com.zc.manager.device.request.DeviceGatewayMessageCountRequest;
import com.zc.manager.device.request.DeviceMessageCountRequest;
import com.zc.manager.device.service.ApiIotMetricsService;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;

import javax.annotation.Resource;
import java.util.*;

@Service
public class ApiIotMetricsServiceImpl implements ApiIotMetricsService {

    @Resource
    private DashboardManager dashboardManager;

    /**
     * 获取设备消息计数
     *
     * @param request 包含设备消息计数请求的参数，例如设备ID等。
     * @return 计数结果，返回消息的数量。
     */
    @Override
    public int deviceGatewayMessageCount(DeviceGatewayMessageCountRequest request) {

        List<DashboardMeasurementRequest> dashboardMeasurementRequestList = new ArrayList<>();

        DashboardMeasurementRequest dashboardMeasurementRequest = new DashboardMeasurementRequest();

        Map<String, Object> params = new HashMap<>();

        dashboardMeasurementRequest.setDashboard("gatewayMonitor");
        dashboardMeasurementRequest.setObject("deviceGateway");
        dashboardMeasurementRequest.setMeasurement(request.getDirection());

        dashboardMeasurementRequest.setGroup("device_msg");
        dashboardMeasurementRequest.setDimension("agg");

        //params.put("limit", 1);
        params.put("time", request.convertPeriodType());
        // params.put("format", "yyyy-MM-dd HH:mm:ss");
        params.put("from", DateUtil.formatDateTime(request.getStartTime()));
        params.put("to", DateUtil.formatDateTime(request.getEndTime()));

        dashboardMeasurementRequest.setParams(params);

        dashboardMeasurementRequestList.add(dashboardMeasurementRequest);

        return getDashboardMeasurement(dashboardMeasurementRequestList);
    }

    /**
     * 获取设备消息计数
     *
     * @param request 包含设备消息计数请求的参数，例如设备ID等。
     * @return 计数结果，返回消息的数量。
     */
    @Override
    public int deviceMessageCount(DeviceMessageCountRequest request) {
        List<DashboardMeasurementRequest> dashboardMeasurementRequestList = new ArrayList<>();

        DashboardMeasurementRequest dashboardMeasurementRequest = new DashboardMeasurementRequest();

        Map<String, Object> params = new HashMap<>();

        dashboardMeasurementRequest.setDashboard("device");
        dashboardMeasurementRequest.setObject("message");
        dashboardMeasurementRequest.setMeasurement("quantity");
        dashboardMeasurementRequest.setGroup("device_msg");
        dashboardMeasurementRequest.setDimension("agg");

        //params.put("limit", 1);
        params.put("time", request.convertPeriodType());
        // params.put("format", "yyyy-MM-dd HH:mm:ss");
        params.put("from", DateUtil.formatDateTime(request.getStartTime()));
        params.put("to", DateUtil.formatDateTime(request.getEndTime()));
        params.put("productId", request.getProductId());
        params.put("msgType", request.getMsgType());

        dashboardMeasurementRequest.setParams(params);

        dashboardMeasurementRequestList.add(dashboardMeasurementRequest);

        return getDashboardMeasurement(dashboardMeasurementRequestList);
    }

    /**
     * 根据提供的仪表盘测量请求列表，获取仪表盘测量值的总和。
     *
     * @param dashboardMeasurementRequestList 仪表盘测量请求列表，包含需要获取测量值的仪表盘、对象、测量维度等信息。
     * @return 返回测量值的总和。如果没有任何有效测量值，则返回0。
     */
    public int getDashboardMeasurement(List<DashboardMeasurementRequest> dashboardMeasurementRequestList) {

        // 从请求列表中创建Flux流，并对每个请求进行处理：获取仪表盘、对象、测量值和维度，然后过滤掉实时维度数据，最后获取测量值。
        Flux<DashboardMeasurementResponse> result = Flux.fromIterable(dashboardMeasurementRequestList).flatMap(request -> dashboardManager
                .getDashboard(request.getDashboard())
                .flatMap(dash -> dash.getObject(request.getObject()))
                .flatMap(obj -> obj.getMeasurement(request.getMeasurement()))
                .flatMap(meas -> meas.getDimension(request.getDimension()))
                .filter(dim -> !dim.isRealTime()) // 过滤掉实时数据，推荐使用EventSource方式获取实时数据
                .flatMapMany(dim -> dim.getValue(MeasurementParameter.of(request.getParams())))
                .map(val -> DashboardMeasurementResponse.of(request.getGroup(), val)));

        // 将Flux流收集到List中
        List<DashboardMeasurementResponse> list = result.collectList().block();
        if (list == null || list.isEmpty()) {
            return 0; // 如果没有有效数据，则返回0
        }

        // 对收集到的测量响应列表进行处理，获取每个响应的测量值并求和
        return list.stream().map(DashboardMeasurementResponse::getData) // 获取每个对象的data属性
                .filter(Objects::nonNull) // 过滤掉null值，防止影响求和
                .mapToInt(measurementValue ->  {
                    if (measurementValue instanceof SimpleMeasurementValue) {
                        return (int)((SimpleMeasurementValue) measurementValue).getValue();
                    }
                    return 0; // 如果测量值不是预期类型，则默认为0
                })
                .sum(); // 对所有值求和
    }


}
